#include "StdAfx.h"
#include "MerryRoundFactory.h"
#include "SgRegularPolygon.h"
#include "SgMaterial.h"
#include "math.h"
#include "ChildView.h"
#include "AnimationRotateMerrySpin.h"
#include "AnimationRotateMerryLift.h"
const double Pi = std::atan(1.0)*4;

CMerryRoundFactory::CMerryRoundFactory(void)
: m_root(NULL)
, m_spinangle(0)
{
	corntex = new CSgTexture(L"Grass.bmp"); 
	pillar_tex = new CSgTexture(L"mirror.bmp");
	roof_tex1 = new CSgTexture(L"teak01.bmp");
	roof_tex2 = new CSgTexture(L"teak01.bmp");
	horse_tex1 = new CSgTexture(L"leopard.bmp");
	floor_tex1 = new CSgTexture(L"yinyang.bmp");
}

CMerryRoundFactory::~CMerryRoundFactory(void)
{
}

/*
 *        Name: Create()
 * Description: Create the ride and move to proper place
 *  Parameters: root -  the scene graph 
 */
void CMerryRoundFactory::Create(CSgComposite* root)
{
	m_root=root;
	CSgPtr<CSgMaterial> ride = new CSgMaterial();
	CreateBase(ride);
	CSgPtr<CSgTranslate> tran2 = new CSgTranslate(40,3,-92);
	tran2->AddChild(ride);
	m_root->AddChild(tran2);
}

/*
 *        Name: CreateBase()
 * Description: Create the spinnable base and central pillar, and map the animation movement
 *  Parameters: parent -  the parent scene graph node
 */
void CMerryRoundFactory::CreateBase(CSgComposite* parent)
{
	CSgPtr<CSgMaterial> pillar_comp = new CSgMaterial();
	CSgPtr<CSgRegularCylinder> pillar = new CSgRegularCylinder();
	pillar->SetMapping(1); //Set the texture coordinate mode, default 0 means wrap around the cylinder, 1 means each face map one image
	pillar->SetProperties(6,14.,3.);
	pillar_comp->AddChild(pillar);
	CSgPtr<CSgTranslate> pillar_tran1 = new CSgTranslate(0.,2.,0.);
	pillar_tran1->AddChild(pillar_comp);	
	pillar_tex->AddChild(pillar_tran1);
	CSgPtr<CSgRotateAroundPoint> rap4 = new CSgRotateAroundPoint(); //Set initial spin angle for the later animation
	rap4->SetNormal(0,1,0);
	rap4->SetAngle(0);
	rap4->SetPoint(CGrVector(0,4,0));
	rap4->AddChild(pillar_tex);
	CSgPtr<CAnimationRotateMerrySpin> merryspin3 = new CAnimationRotateMerrySpin(); //Create animation pointer merryspin3
	merryspin3->SetNode(rap4);
	m_timeline->AddChannel(merryspin3);
	parent->AddChild(rap4);


	//Change the size and orientation of the model
	CSgPtr<CSgTransform> horse_tran2 = new CSgTransform();
	horse_tran2->SetTranslate(0,4,0);
	horse_tran2->SetRotate(90,0,1,0);
	horse_tran2->SetRotate(90,-1,0,0);
	horse_tran2->SetScale(0.03,0.03,0.03);	
	/*This look create 3 horses with rods around the base circle*/
	for(int i=0; i<3; i++){
	
		CSgPtr<CSgTranslate> rod_tran1 = new CSgTranslate(8.*sin(2*Pi*i/3),3.+i,8.*cos(2*Pi*i/3)); //map the horses around the base of ride
		CreateHorse(rod_tran1);
		CSgPtr<CAnimationRotateMerryLift> merrylift = new CAnimationRotateMerryLift();
		merrylift->SetNode(rod_tran1);
		m_timeline->AddChannel(merrylift);

		CSgPtr<CSgMaterial> horse_mat = new CSgMaterial();  
		horse_mat->SetDiffuseColor(0.5f,0.2f, 0.1f,1.0f);
		horse_mat->SetSpecularColor(0.5f,0.2f, 0.1f,1.0f);
		horse_mat->AddChild(rod_tran1);
		CSgPtr<CSgRotateAroundPoint> rap4 = new CSgRotateAroundPoint();  
		rap4->SetNormal(0,1,0);
		rap4->SetAngle(-60*i);  //set the orientation of horse on the rod
		if(i==1) rap4->SetAngle(75);
		rap4->SetPoint(CGrVector(8.*sin(2*Pi*i/3),0,8.*cos(2*Pi*i/3)));
		rap4->AddChild(horse_mat);

		CSgPtr<CSgRotateAroundPoint> rap1 = new CSgRotateAroundPoint();
		rap1->SetNormal(0,1,0);
		rap1->SetAngle(0);
		rap1->SetPoint(CGrVector(0,4,0));
		rap1->AddChild(rap4);
		CSgPtr<CAnimationRotateMerrySpin> merryspin = new CAnimationRotateMerrySpin(); //Set the animation of horses' spin
		merryspin->SetNode(rap1);
		m_timeline->AddChannel(merryspin);
		parent->AddChild(rap1);
		
		
		CSgPtr<CSgTransform> horse_tran1 = new CSgTransform();
		horse_tran1->SetTranslate(8.*sin(2*Pi*i/3),2.,8.*cos(2*Pi*i/3)); //map the rods around the base of ride
		CSgPtr<CSgMaterial> rods = new CSgMaterial();
		CreateRod(rods);
		horse_tran1->AddChild(rods);
		CSgPtr<CSgRotateAroundPoint> rap2 = new CSgRotateAroundPoint();
		rap2->SetNormal(0,1,0);
		rap2->SetAngle(0);
		rap2->SetPoint(CGrVector(0,4,0));
		rap2->AddChild(horse_tran1);
		CSgPtr<CAnimationRotateMerrySpin> merryspin2 = new CAnimationRotateMerrySpin();  //Set the animation of rods' spin
		merryspin2->SetNode(rap2);
		m_timeline->AddChannel(merryspin2);
		parent->AddChild(rap2);	
	}	

	CSgPtr<CSgTranslate> roof_tran1 = new CSgTranslate(0.,1.,0);   //the small base floor with leopard side and yinyang top

	CSgPtr<CSgMaterial> roof = new CSgMaterial();
	roof->SetDiffuseColor(0.2f,0.2f,0.9f,1.f);
	roof->SetSpecularColor(0.2f,0.2f,0.9f,1.f);
	CreateRoof(roof);
	roof_tran1->AddChild(roof);
	parent->AddChild(roof_tran1);

	//the big base using mesh
	CSgPtr<CSgMaterial> testmesh = new CSgMaterial();
	testmesh->SetDiffuseColor(0.8f,0.1f,0.2f,1.0f);
	testmesh->SetSpecularColor(0.8f,0.1f,0.2f,1.0f);
	CSgPtr<CSgTransform> mesh_rot = new CSgTransform();
	mesh_rot->SetRotate(90,1,0,0);
	mesh_rot->SetTranslate(0,1,0);
	mesh_rot->AddChild(testmesh);
	CreateFence(mesh_rot);
	CSgPtr<CSgPolygon> baseTop = new CSgPolygon(); //the blue surface of big base
	baseTop->AddNormal(CGrVector(0, -1, 0));
	for (double i = 36; i > 0; i--)
	{
		GLdouble start[] = {20*cos(i*2*Pi/36+2*Pi/(36*2.0)),0.0,20*sin(i*2*Pi/36+2*Pi/(36*2.0))};
		baseTop->AddVertex3dv(start);
		baseTop->AddTexCoord(CGrVector((cos(i * 2 * Pi / 36)/2) + 0.5, (sin(i * 2 * Pi / 36)/2) + 0.5, 1));
	}
	CSgPtr<CSgTranslate> baseTop_up = new CSgTranslate(0,1,0);
	baseTop_up->AddChild(baseTop);
	parent->AddChild(baseTop_up);
	parent->AddChild(mesh_rot);
}



void CMerryRoundFactory::CreateRoof(CSgComposite* parent)
{
	CSgPtr<CSgMaterial> roof_comp = new CSgMaterial();
	CSgPtr<CSgRegularCylinder> roof = new CSgRegularCylinder();
	roof->SetMapping(1);
	roof->SetProperties(36,1.,13.);
	roof_comp->AddChild(roof);
	CSgPtr<CSgPolygon> floorTop = new CSgPolygon(); //the yinyang surface of small base
	floorTop->AddNormal(CGrVector(0, -1, 0));
	for (double i = 36; i > 0; i--)
	{
		GLdouble start[] = {13*cos(i*2*Pi/36+2*Pi/(36*2.0)),0.0,13*sin(i*2*Pi/36+2*Pi/(36*2.0))};
		floorTop->AddVertex3dv(start);
		floorTop->AddTexCoord(CGrVector((cos(i * 2 * Pi / 36)/2) + 0.5, (sin(i * 2 * Pi / 36)/2) + 0.5, 1));
	}
	floor_tex1->AddChild(floorTop);
	CSgPtr<CSgMaterial> floor_top = new CSgMaterial();
	floor_top->AddChild(floor_tex1);
	CSgPtr<CSgTranslate> floor_up = new CSgTranslate(0,1.1,0);
	floor_up->AddChild(floor_top);
	roof_comp->AddChild(floor_up);
	horse_tex1->AddChild(roof_comp);

	CSgPtr<CSgRotateAroundPoint> rap4 = new CSgRotateAroundPoint();
	rap4->SetNormal(0,1,0);
	rap4->SetAngle(0);
	rap4->SetPoint(CGrVector(0,4,0));
	rap4->AddChild(horse_tex1);
	CSgPtr<CAnimationRotateMerrySpin> merryspin4 = new CAnimationRotateMerrySpin();
	merryspin4->SetNode(rap4);
	m_timeline->AddChannel(merryspin4);

	parent->AddChild(rap4);
	CSgPtr<CSgTransform> roof_tran2 = new CSgTransform();
	roof_tran2->SetTranslate(0,17,0);
	CSgPtr<CSgComposite> roof_comp2 = new CSgComposite();
	CSgPtr<CSgRegularCylinder> roof2 = new CSgRegularCylinder();
	roof2->SetMapping(1);
	roof2->SetProperties(36,2.,13.);
	
	CSgPtr<CSgTransform> roof_tran3 = new CSgTransform();
	roof_tran3->SetTranslate(0,15,0);
	roof_tran3->AddChild(roof2);
	roof_tex2->AddChild(roof_tran3);
	parent->AddChild(roof_tex2);
	CSgPtr<CSgComposite> corntex = new CSgComposite();
	CreateCorn(corntex);
	roof_tran2->AddChild(corntex);

	CSgPtr<CSgRotateAroundPoint> rap3 = new CSgRotateAroundPoint();
	rap3->SetNormal(0,1,0);
	rap3->SetAngle(0);
	rap3->SetPoint(CGrVector(0,4,0));
	rap3->AddChild(roof_tran2);
	CSgPtr<CAnimationRotateMerrySpin> merryspin3 = new CAnimationRotateMerrySpin();
	merryspin3->SetNode(rap3);
	m_timeline->AddChannel(merryspin3);

	
	parent->AddChild(rap3);
}
/*
 *        Name: CreateHorse()
 * Description: Create the horse and adjust to proper size and position
 *  Parameters: parent -  the parent scene graph node
 */
void CMerryRoundFactory::CreateHorse(CSgComposite* parent)
{
	CSgPtr<CSgComposite> horse2 = new CSgComposite();
	CreateHorse2(horse2);
	CSgPtr<CSgTransform> horse_up = new CSgTransform();
	horse_up->SetTranslate(0,3,0);
	horse_up->SetScale(0.7,0.7,0.7);
	horse_up->AddChild(horse2);
	parent->AddChild(horse_up);
}


/*
 *        Name: CreateCorn()
 * Description: Create the cone-like roof with 3 colors
 *  Parameters: parent -  the parent scene graph node
 */
void CMerryRoundFactory::CreateCorn(CSgComposite* parent)
{
	CSgPtr<CSgPolygon> triangle2 = new CSgPolygon(); //Create a triangle component at x-z plane 
	triangle2->AddVertex3d(0,0,0);
	triangle2->AddTexCoord(CGrVector(0,0));
	triangle2->AddVertex3d(18*cos(2*Pi*4.4/360)*cos(2*Pi*30/360),0,-18*sin(2*Pi*4.4/360));
	triangle2->AddTexCoord(CGrVector(0,1));
	triangle2->AddVertex3d(18*cos(2*Pi*4.4/360)*cos(2*Pi*30/360),0,18*sin(2*Pi*4.4/360));
	triangle2->AddTexCoord(CGrVector(1,1));
	triangle2->AddNormal(CGrVector(0,-1,0));
	
	//create 36 triangles around to make a circle
	for(int i=0; i<36; i++){
		CSgPtr<CSgTransform> corn_tran4 = new CSgTransform();
		corn_tran4->SetRotate(10*i,0,1,0);
		corn_tran4->AddChild(triangle2);
		parent->AddChild(corn_tran4);
	}
	for(int i=0; i<36; i++){
	CSgPtr<CSgPolygon> triangle1 = new CSgPolygon();
	triangle1->AddVertex3d(0,0,0);
	triangle1->AddTexCoord(CGrVector(0,0));
	triangle1->AddVertex3d(18*cos(2*Pi*4.4/360),0,18*sin(2*Pi*4.4/360));
	triangle1->AddTexCoord(CGrVector(0,1));
	triangle1->AddVertex3d(18*cos(2*Pi*4.4/360),0,-18*sin(2*Pi*4.4/360));
	triangle1->AddTexCoord(CGrVector(i%2/2,1));
	triangle1->AddNormal(CGrVector(0.866,0.5,0));
	CSgPtr<CSgTransform> corn_tran1 =new CSgTransform();
	corn_tran1->SetTranslate(0,18*cos(2*Pi*4.4/360)*sin(2*Pi*30/360),0);
	CSgPtr<CSgTransform> corn_tran2 = new CSgTransform();
	CSgPtr<CSgTransform> corn_tran3 = new CSgTransform();
	CSgPtr<CSgComposite> corn_comp = new CSgComposite();
	corn_tran2->SetRotate(30,0,0,-1);
	corn_tran3->SetRotate(10*i,0,1,0);
	corn_comp->AddChild(triangle1);
	corn_tran2->AddChild(corn_comp);
	corn_tran1->AddChild(corn_tran2);
	corn_tran3->AddChild(corn_tran1);
	CSgPtr<CSgMaterial> corn_mat = new CSgMaterial();

	if(i%3==0){
		corn_mat->SetDiffuseColor(.87f, .08f, .16f, 1.f);
		corn_mat->SetSpecularColor(.87f, .08f, .16f, 1.f);
	}
	if(i%3==1){
		corn_mat->SetDiffuseColor(.47f, .38f, .66f, 1.f);
		corn_mat->SetSpecularColor(.47f, .38f, .66f, 1.f);
	}
	if(i%3==2){
		corn_mat->SetDiffuseColor(.27f, .18f, .76f, 1.f);
		corn_mat->SetSpecularColor(.27f, .18f, .76f, 1.f);
	}

	corn_mat->AddChild(corn_tran3);
	parent->AddChild(corn_mat);
	}

}

/*
 *        Name: CreateHorse2()
 * Description: Create the horse
 *  Parameters: parent -  the parent scene graph node
 */
void CMerryRoundFactory::CreateHorse2(CSgComposite* parent)
{
	CSgPtr<CSgComposite> horse = new CSgComposite();

	CSgPtr<CSgRegularCylinder> body = new CSgRegularCylinder();
	CSgPtr<CSgRegularCylinder> neck = new CSgRegularCylinder();
	CSgPtr<CSgRegularCylinder> head = new CSgRegularCylinder();
	CSgPtr<CSgRegularCylinder> leg = new CSgRegularCylinder();
	CSgPtr<CSgRegularCylinder> tail = new CSgRegularCylinder();
	CSgPtr<CSgRegularCylinder> ear = new CSgRegularCylinder();
	

	body->SetProperties(8,4.5,1.5);	
	neck->SetProperties(8,4,0.5);
	head->SetProperties(8,3,1);
	tail->SetProperties(8,2,0.2);
	leg->SetProperties(8,4,0.4);
	ear->SetProperties(8,0.6,0.3);

	CSgPtr<CSgTransform> body_tran1 = new CSgTransform();
	body_tran1->SetRotate(90,0,0,1);

	CSgPtr<CSgTransform> neck_tran1 = new CSgTransform();
	neck_tran1->SetRotate(45,0,0,1);
	neck_tran1->SetTranslate(-3,0,-0.2);
	
	CSgPtr<CSgTransform> head_tran1 = new CSgTransform();
	head_tran1->SetRotate(110,0,0,1);
	head_tran1->SetTranslate(-5,3.5,-0.2);

	CSgPtr<CSgTransform> tail_tran1 = new CSgTransform();
	tail_tran1->SetRotate(120,0,0,1);
	tail_tran1->SetTranslate(1.7,0.5,-0.2);

	CSgPtr<CSgTransform> leg_tran1 = new CSgTransform();
	leg_tran1->SetRotate(30,0,0,1);
	leg_tran1->SetTranslate(-0.1,-4,1);
	leg_tran1->SetRotate(-30,1,0,0);
	leg_tran1->SetRotate(30,0,0,1);
	leg_tran1->AddChild(leg);
	//parent->AddChild(leg_tran1);
	
	CSgPtr<CSgTransform> leg_tran2 = new CSgTransform();
	leg_tran2->SetRotate(30,0,0,1);
	leg_tran2->SetTranslate(-0.1,-4,-1);
	leg_tran2->SetRotate(30,1,0,0);
	leg_tran2->SetRotate(30,0,0,1);
	leg_tran2->AddChild(leg);
	//parent->AddChild(leg_tran2);

	CSgPtr<CSgComposite> legs = new CSgComposite();
	legs->AddChild(leg_tran1);
	legs->AddChild(leg_tran2);
	horse->AddChild(legs);

	CSgPtr<CSgTransform> frontleg_tran = new CSgTransform();
	frontleg_tran->SetTranslate(-1.5,-1.5,0);
	frontleg_tran->SetRotate(60,0,0,-1);
	frontleg_tran->AddChild(legs);
	horse->AddChild(frontleg_tran);

	CSgPtr<CSgComposite> ears = new CSgComposite();
	CSgPtr<CSgTransform> ear_tran1 = new CSgTransform();
	ear_tran1->SetRotate(30,1,0,0);
	ear_tran1->SetTranslate(-6.5,3.8,0.2);
	ear_tran1->AddChild(ear);
	CSgPtr<CSgTransform> ear_tran2 = new CSgTransform();
	ear_tran2->SetRotate(30,-1,0,0);
	ear_tran2->SetTranslate(-6.5,3.8,-0.5);
	ear_tran2->AddChild(ear);
	ears->AddChild(ear_tran1);
	ears->AddChild(ear_tran2);
	horse->AddChild(ears);


	body_tran1->AddChild(body);
	neck_tran1->AddChild(neck);
	head_tran1->AddChild(head);
	tail_tran1->AddChild(tail);
	
	horse->AddChild(neck_tran1);
	horse->AddChild(head_tran1);
	horse->AddChild(body_tran1);
	horse->AddChild(tail_tran1);

	CSgPtr<CSgTransform> adjust = new CSgTransform();
	adjust->SetTranslate(2,0,0);
	adjust->AddChild(horse);
	parent->AddChild(adjust);	
}

/*
 *        Name: CreateRod()
 * Description: Create the rods
 *  Parameters: parent -  the parent scene graph node
 */
void CMerryRoundFactory::CreateRod(CSgComposite* parent)
{
	CSgPtr<CSgComposite> rod_comp = new CSgComposite();
	CSgPtr<CSgRegularCylinder> rod = new CSgRegularCylinder();
	rod->SetMapping(1);
	rod->SetProperties(15,14.,0.3);
	roof_tex1->AddChild(rod);
	rod_comp->AddChild(roof_tex1);
	parent->AddChild(rod_comp);
}

/*
 *        Name: CreateFence()
 * Description: Create the big base using mesh
 *  Parameters: parent -  the parent scene graph node
 */
void CMerryRoundFactory::CreateFence(CSgComposite * parent)
{
	double(*p)[4] = new double[72][4];
	double(*q)[4] = new double[72][4];
	double radium=20;
	for(int i=0; i<72; i++){
		double a = 5.*i*2.*Pi/360.;
		p[i][0]=q[i][0]=radium*cos(a);
		p[i][1]=q[i][1]=radium*sin(a);
		p[i][2]=0;
		q[i][2]=3;
		p[i][3]=q[i][3]=1.;
	}


	CSgPtr<CSgMesh> m_mesh = new CSgMesh();
	for(int i=0; i<72; i++){
		m_mesh->AddVertex(CGrVector(p[i][0],p[i][1],p[i][2]));
		m_mesh->AddVertex(CGrVector(q[i][0],q[i][1],q[i][2]));
	}

	for(int k=0; k<=142; k++){
		GLdouble normal[] = {(p[k][0]+p[k+1][0])/2,(p[k][1]+p[k+1][1])/2,0.};
		Normalize(normal);
		m_mesh->AddNormal(normal);
		if(k%2==0&&k!=142)
		m_mesh->AddFlatQuad(k,k+2,k+3,k+1, k);
		if(k==142)
		m_mesh->AddFlatQuad(k,0,1,k+1,k);
	}
	CSgPtr<CSgTransform> mesh_rot1 = new CSgTransform();
	mesh_rot1->SetRotate(120,0,0,1);
	mesh_rot1->AddChild(m_mesh);
	parent->AddChild(mesh_rot1);
	delete[] p;
	delete[] q;
}
